home *** CD-ROM | disk | FTP | other *** search
/ Aminet 6 / Aminet 6 - June 1995.iso / Aminet / gfx / 3d / irit50src.lha / irit5 / prsr_lib / bsp_read.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-29  |  18.2 KB  |  515 lines

  1. /******************************************************************************
  2. * Bsp_Read.c - Bspline handling routines - read from file.              *
  3. *******************************************************************************
  4. * Written by Gershon Elber, Aug. 90.                          *
  5. ******************************************************************************/
  6.  
  7. #include <ctype.h>
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include "prsr_loc.h"
  11.  
  12. /*****************************************************************************
  13. * DESCRIPTION:                                                               M
  14. * Reads from a file Bspline curve(s).                         M
  15. *   If error is detected in reading the file, ErrStr is set to a string      M
  16. * describing the error and Line to the line it occured in file.             M
  17. *   If no error is detected *ErrStr = NULL.                     M
  18. *                                                                            *
  19. * PARAMETERS:                                                                M
  20. *   FileName:     To read the Bspline curve from.                            M
  21. *   ErrStr:       Will be initialized if an error has occured.               M
  22. *   ErrLine:      Line number in file FileName of the error, if occured.     M
  23. *                                                                            *
  24. * RETURN VALUE:                                                              M
  25. *   CagdCrvStruct *: The read curve, or NULL if an error occured.            M
  26. *                                                                            *
  27. * KEYWORDS:                                                                  M
  28. *   BspCrvReadFromFile, files, read                                          M
  29. *****************************************************************************/
  30. CagdCrvStruct *BspCrvReadFromFile(char *FileName, char **ErrStr, int *ErrLine)
  31. {
  32.     int Handler;
  33.     FILE *f;
  34.     char StringToken[LINE_LEN];
  35.     CagdCrvStruct *Crv,
  36.     *CrvTail = NULL,
  37.     *CrvList = NULL;
  38.  
  39.     if ((f = fopen(FileName, "r")) == NULL) {
  40.     *ErrStr = "File not found";
  41.     *ErrLine = 0;
  42.     return NULL;
  43.     }
  44.     Handler = IritPrsrOpenStreamFromFile(f, TRUE,
  45.                      IritPrsrSenseBinaryFile(FileName),
  46.                      FALSE);
  47.  
  48.     while (_IPGetToken(Handler, StringToken) == IP_TOKEN_OPEN_PAREN) {
  49.     _IPUnGetToken(Handler, StringToken);
  50.         Crv = BspCrvReadFromFile2(Handler, FALSE, ErrStr, ErrLine);
  51.  
  52.     if (CrvList == NULL)
  53.         CrvList = CrvTail = Crv;
  54.     else {
  55.         CrvTail -> Pnext = Crv;
  56.         CrvTail = Crv;
  57.     }
  58.     }
  59.  
  60.     IritPrsrCloseStream(Handler, TRUE);
  61.  
  62.     return CrvList;
  63. }
  64.  
  65. /*****************************************************************************
  66. * DESCRIPTION:                                                               M
  67. * Reads from a file a Bspline curve.                         M
  68. *   If NameWasRead is TRUE, it is assumed prefix "[CURVE BSPLINE" has        M
  69. * already been read. This is useful for a global parser which invokes this   M
  70. * routine to read from a file several times as a parent controller.          M
  71. *   For exactly this reason, the given file descriptor is NOT closed in the  M
  72. * end.                                         M
  73. *   If error is found in reading the file, ErrStr is set to a string         M
  74. * describing it and ErrLine to line it occured in file relative to begining  M
  75. * of curve.                                      M
  76. *   If no error is detected *ErrStr is set to NULL.                 M
  77. *                                                                            *
  78. * PARAMETERS:                                                                M
  79. *   Handler:      A handler to the open stream.                     M
  80. *   NameWasRead: TRUE if "[CURVE BSPLINE" has been read, FALSE otherwise.    M
  81. *   ErrStr:       Will be initialized if an error has occured.               M
  82. *   ErrLine:      Line number in file FileName of the error, if occured.     M
  83. *                                                                            *
  84. * RETURN VALUE:                                                              M
  85. *   CagdCrvStruct *: The read curve, or NULL if an error occured.            M
  86. *                                                                            *
  87. * KEYWORDS:                                                                  M
  88. *   BspCrvReadFromFile2, files, read, stream                                 M
  89. *****************************************************************************/
  90. CagdCrvStruct *BspCrvReadFromFile2(int Handler,
  91.                    CagdBType NameWasRead,
  92.                    char **ErrStr,
  93.                    int *ErrLine)
  94. {
  95.     CagdPointType PType;
  96.     IPTokenType Token;
  97.     int i, j, Length, Order, MaxCoord, KVPeriodic;
  98.     char StringToken[LINE_LEN];
  99.     CagdCrvStruct *NewCrv;
  100.  
  101.     if (!NameWasRead) {
  102.     while ((Token = _IPGetToken(Handler, StringToken)) != IP_TOKEN_EOF &&
  103.            Token != IP_TOKEN_OPEN_PAREN);
  104.  
  105.     /* We found beginning of definition - read one: */
  106.     if (_IPGetToken(Handler, StringToken) != IP_TOKEN_CURVE ||
  107.         _IPGetToken(Handler, StringToken) != IP_TOKEN_BSPLINE) {
  108.             *ErrStr = "CURVE BSPLINE key words expected";
  109.         *ErrLine = _IPStream[Handler].LineNum;
  110.         return NULL;
  111.     }
  112.     }
  113.  
  114.     if ((Token = _IPGetToken(Handler, StringToken)) == IP_TOKEN_OPEN_PAREN) {
  115.     if ((*ErrStr = _IPGetCurveAttributes(Handler)) != NULL) {
  116.             *ErrStr = "\"[\" expected";
  117.         *ErrLine = _IPStream[Handler].LineNum;
  118.         return NULL;
  119.     }
  120.     }
  121.     else
  122.     _IPUnGetToken(Handler, StringToken);
  123.  
  124.     if ((Token = _IPGetToken(Handler, StringToken)) != IP_TOKEN_OTHER ||
  125.     sscanf(StringToken, "%d", &Length) != 1) {
  126.     *ErrStr = "BSPLINE Number of points expected";
  127.     *ErrLine = _IPStream[Handler].LineNum;
  128.     return NULL;
  129.     }
  130.  
  131.     if ((Token = _IPGetToken(Handler, StringToken)) != IP_TOKEN_OTHER ||
  132.     sscanf(StringToken, "%d", &Order) != 1) {
  133.     *ErrStr = "BSPLINE Order expected";
  134.     *ErrLine = _IPStream[Handler].LineNum;
  135.     return NULL;
  136.     }
  137.  
  138.     Token = _IPGetToken(Handler, StringToken);
  139.     if (!IP_IS_TOKEN_POINT(Token) ||
  140.     strlen(StringToken) != 2 ||
  141.     (StringToken[0] != 'E' && StringToken[0] != 'P') ||
  142.     !isdigit(StringToken[1]) ||
  143.     atoi(&StringToken[1]) > CAGD_MAX_PT_COORD) {
  144.     *ErrStr = "BSPLINE Point type expected";
  145.     *ErrLine = _IPStream[Handler].LineNum;
  146.     return NULL;
  147.     }
  148.  
  149.     PType = CAGD_MAKE_PT_TYPE(StringToken[0] == 'P', atoi(&StringToken[1]));
  150.  
  151.     /* Read the knot vector first: */
  152.     if ((Token = _IPGetToken(Handler, StringToken)) != IP_TOKEN_OPEN_PAREN) {
  153.     *ErrStr = "\"[\" expected";
  154.     *ErrLine = _IPStream[Handler].LineNum;
  155.     return NULL;
  156.     }
  157.     if ((Token = _IPGetToken(Handler, StringToken)) != IP_TOKEN_KV) {
  158.     if (Token == IP_TOKEN_KVP) {
  159.         KVPeriodic = TRUE;
  160.     }
  161.     else {
  162.         *ErrStr = "KV expected";
  163.         *ErrLine = _IPStream[Handler].LineNum;
  164.         return NULL;
  165.     }
  166.     }
  167.     else
  168.     KVPeriodic = FALSE;
  169.  
  170.     NewCrv = KVPeriodic ? BspPeriodicCrvNew(Length, Order, TRUE, PType)
  171.             : BspCrvNew(Length, Order, PType);
  172.  
  173.     for (i = 0; i < Order + Length + (KVPeriodic ? Order - 1 : 0); i++) {
  174.     if ((Token = _IPGetToken(Handler, StringToken)) != IP_TOKEN_OTHER ||
  175.         sscanf(StringToken, IP_FLOAT_READ,
  176.                          &NewCrv -> KnotVector[i]) != 1) {
  177.         *ErrStr = "Numeric data expected";
  178.         *ErrLine = _IPStream[Handler].LineNum;
  179.         CagdCrvFree(NewCrv);
  180.         return NULL;
  181.     }
  182.     }
  183.     if ((Token = _IPGetToken(Handler, StringToken)) != IP_TOKEN_CLOSE_PAREN) {
  184.     *ErrStr = "\"]\" expected";
  185.     *ErrLine = _IPStream[Handler].LineNum;
  186.     CagdCrvFree(NewCrv);
  187.     return NULL;
  188.     }
  189.  
  190.     /* Read the points themselves: */
  191.     MaxCoord = CAGD_NUM_OF_PT_COORD(PType);
  192.     for (i = 0; i < Length; i++) {
  193.     if ((Token = _IPGetToken(Handler, StringToken)) !=
  194.                             IP_TOKEN_OPEN_PAREN) {
  195.         *ErrStr = "\"[\" expected";
  196.         *ErrLine = _IPStream[Handler].LineNum;
  197.         CagdCrvFree(NewCrv);
  198.         return NULL;
  199.     }
  200.     if (CAGD_IS_RATIONAL_PT(PType)) {
  201.         if ((Token = _IPGetToken(Handler, StringToken)) !=
  202.                             IP_TOKEN_OTHER ||
  203.         sscanf(StringToken, IP_FLOAT_READ,
  204.                            &NewCrv -> Points[0][i]) != 1) {
  205.         *ErrStr = "Numeric data expected";
  206.         *ErrLine = _IPStream[Handler].LineNum;
  207.         CagdCrvFree(NewCrv);
  208.         return NULL;
  209.         }
  210.     }
  211.     for (j = 1; j <= MaxCoord; j++) {
  212.         if ((Token = _IPGetToken(Handler, StringToken)) !=
  213.                             IP_TOKEN_OTHER ||
  214.         sscanf(StringToken, IP_FLOAT_READ,
  215.                            &NewCrv -> Points[j][i]) != 1) {
  216.         *ErrStr = "Numeric data expected";
  217.         *ErrLine = _IPStream[Handler].LineNum;
  218.         CagdCrvFree(NewCrv);
  219.         return NULL;
  220.         }
  221.     }
  222.     if ((Token = _IPGetToken(Handler, StringToken)) !=
  223.                             IP_TOKEN_CLOSE_PAREN) {
  224.         *ErrStr = "\"]\" expected";
  225.         *ErrLine = _IPStream[Handler].LineNum;
  226.         CagdCrvFree(NewCrv);
  227.         return NULL;
  228.     }
  229.     }
  230.     if ((Token = _IPGetToken(Handler, StringToken)) != IP_TOKEN_CLOSE_PAREN) {
  231.     *ErrStr = "\"]\" expected";
  232.     *ErrLine = _IPStream[Handler].LineNum;
  233.     CagdCrvFree(NewCrv);
  234.     return NULL;
  235.     }
  236.  
  237.     *ErrLine = _IPStream[Handler].LineNum;
  238.     *ErrStr = NULL;
  239.  
  240.     return NewCrv;
  241. }
  242.  
  243. /*****************************************************************************
  244. * DESCRIPTION:                                                               M
  245. * Reads from a file Bspline surface(s).                         M
  246. *   If error is detected in reading the file, ErrStr is set to a string      M
  247. * describing the error and Line to the line it occured in file.             M
  248. *   If no error is detected *ErrStr = NULL.                     M
  249. *                                                                            *
  250. * PARAMETERS:                                                                M
  251. *   FileName:     To read the Bspline surface from.                          M
  252. *   ErrStr:       Will be initialized if an error has occured.               M
  253. *   ErrLine:      Line number in file FileName of the error, if occured.     M
  254. *                                                                            *
  255. * RETURN VALUE:                                                              M
  256. *   CagdSrfStruct *: The read surface, or NULL if an error occured.          M
  257. *                                                                            *
  258. * KEYWORDS:                                                                  M
  259. *   BspSrfReadFromFile, files, read                                          M
  260. *****************************************************************************/
  261. CagdSrfStruct *BspSrfReadFromFile(char *FileName, char **ErrStr, int *ErrLine)
  262. {
  263.     int Handler;
  264.     FILE *f;
  265.     char StringToken[LINE_LEN];
  266.     CagdSrfStruct *Srf,
  267.     *SrfTail = NULL,
  268.     *SrfList = NULL;
  269.  
  270.     if ((f = fopen(FileName, "r")) == NULL) {
  271.     *ErrStr = "File not found";
  272.     *ErrLine = 0;
  273.     return NULL;
  274.     }
  275.     Handler = IritPrsrOpenStreamFromFile(f, TRUE,
  276.                      IritPrsrSenseBinaryFile(FileName),
  277.                      FALSE);
  278.  
  279.     while (_IPGetToken(Handler, StringToken) == IP_TOKEN_OPEN_PAREN) {
  280.     _IPUnGetToken(Handler, StringToken);
  281.         Srf = BspSrfReadFromFile2(Handler, FALSE, ErrStr, ErrLine);
  282.  
  283.     if (SrfList == NULL)
  284.         SrfList = SrfTail = Srf;
  285.     else {
  286.         SrfTail -> Pnext = Srf;
  287.         SrfTail = Srf;
  288.     }
  289.     }
  290.  
  291.     IritPrsrCloseStream(Handler, TRUE);
  292.  
  293.     return SrfList;
  294. }
  295.  
  296. /*****************************************************************************
  297. * DESCRIPTION:                                                               M
  298. * Reads from a file a Bspline surface.                         M
  299. *   If NameWasRead is TRUE, it is assumed prefix "[SURFACE BSPLINE" has      M
  300. * already been read. This is useful for a global parser which invokes this   M
  301. * routine to read from a file several times as a parent controller.          M
  302. *   For exactly this reason, the given file descriptor is NOT closed in the  M
  303. * end.                                         M
  304. *   If error is found in reading the file, ErrStr is set to a string         M
  305. * describing it and ErrLine to line it occured in file relative to begining  M
  306. * of surface.                                      M
  307. *   If no error is detected *ErrStr is set to NULL.                 M
  308. *                                                                            *
  309. * PARAMETERS:                                                                M
  310. *   Handler:      A handler to the open stream.                     M
  311. *   NameWasRead:  TRUE if "[SURFACE BSPLINE" hasbeen read, FALSE otherwise.  M
  312. *   ErrStr:       Will be initialized if an error has occured.               M
  313. *   ErrLine:      Line number in file FileName of the error, if occured.     M
  314. *                                                                            *
  315. * RETURN VALUE:                                                              M
  316. *   CagdSrfStruct *: The read surface, or NULL if an error occured.          M
  317. *                                                                            *
  318. * KEYWORDS:                                                                  M
  319. *   BspSrfReadFromFile2, files, read, stream                                 M
  320. *****************************************************************************/
  321. CagdSrfStruct *BspSrfReadFromFile2(int Handler,
  322.                    CagdBType NameWasRead,
  323.                    char **ErrStr,
  324.                    int *ErrLine)
  325. {
  326.     int i, j, k, KVLen, ULength, VLength, UOrder, VOrder, MaxCoord;
  327.     char StringToken[LINE_LEN];
  328.     CagdRType *KnotVector;
  329.     CagdPointType PType;
  330.     IPTokenType Token;
  331.     CagdSrfStruct *NewSrf;
  332.  
  333.     if (!NameWasRead) {
  334.     while ((Token = _IPGetToken(Handler, StringToken)) != IP_TOKEN_EOF &&
  335.            Token != IP_TOKEN_OPEN_PAREN);
  336.  
  337.     /* We found beginning of definition - read one: */
  338.     if (_IPGetToken(Handler, StringToken) != IP_TOKEN_SURFACE ||
  339.         _IPGetToken(Handler, StringToken) != IP_TOKEN_BSPLINE) {
  340.         *ErrStr = "SURFACE BSPLINE key words expected";
  341.         *ErrLine = _IPStream[Handler].LineNum;
  342.         return NULL;
  343.         }
  344.     }
  345.  
  346.     if ((Token = _IPGetToken(Handler, StringToken)) == IP_TOKEN_OPEN_PAREN) {
  347.     if ((*ErrStr = _IPGetSurfaceAttributes(Handler)) != NULL) {
  348.         *ErrStr = "\"[\" expected";
  349.         *ErrLine = _IPStream[Handler].LineNum;
  350.         return NULL;
  351.     }
  352.     }
  353.     else
  354.     _IPUnGetToken(Handler, StringToken);
  355.  
  356.     if ((Token = _IPGetToken(Handler, StringToken)) != IP_TOKEN_OTHER ||
  357.         sscanf(StringToken, "%d", &ULength) != 1 ||
  358.     (Token = _IPGetToken(Handler, StringToken)) != IP_TOKEN_OTHER ||
  359.     sscanf(StringToken, "%d", &VLength) != 1) {
  360.     *ErrStr = "BSPLINE Number of points expected";
  361.     *ErrLine = _IPStream[Handler].LineNum;
  362.     return NULL;
  363.     }
  364.     if ((Token = _IPGetToken(Handler, StringToken)) != IP_TOKEN_OTHER ||
  365.     sscanf(StringToken, "%d", &UOrder) != 1 ||
  366.     (Token = _IPGetToken(Handler, StringToken)) != IP_TOKEN_OTHER ||
  367.     sscanf(StringToken, "%d", &VOrder) != 1) {
  368.     *ErrStr = "BSPLINE Order expected";
  369.     *ErrLine = _IPStream[Handler].LineNum;
  370.     return NULL;
  371.     }
  372.  
  373.     Token = _IPGetToken(Handler, StringToken);
  374.     if (!IP_IS_TOKEN_POINT(Token) ||
  375.         strlen(StringToken) != 2 ||
  376.     (StringToken[0] != 'E' && StringToken[0] != 'P') ||
  377.     !isdigit(StringToken[1]) ||
  378.     atoi(&StringToken[1]) > CAGD_MAX_PT_COORD) {
  379.     *ErrStr = "BSPLINE Point type expected";
  380.     *ErrLine = _IPStream[Handler].LineNum;
  381.     return NULL;
  382.     }
  383.     PType = CAGD_MAKE_PT_TYPE(StringToken[0] == 'P', atoi(&StringToken[1]));
  384.  
  385.     NewSrf = BspSrfNew(ULength, VLength, UOrder, VOrder, PType);
  386.  
  387.     /* Read the knot vectors first: */
  388.     for (k = 0; k < 2; k++) {
  389.     int KVPeriodic;
  390.  
  391.         if ((Token = _IPGetToken(Handler, StringToken)) !=
  392.                             IP_TOKEN_OPEN_PAREN) {
  393.             *ErrStr = "\"[\" expected";
  394.         *ErrLine = _IPStream[Handler].LineNum;
  395.         CagdSrfFree(NewSrf);
  396.         return NULL;
  397.         }
  398.         if ((Token = _IPGetToken(Handler, StringToken)) != IP_TOKEN_KV) {
  399.         if (Token == IP_TOKEN_KVP) {
  400.         KVPeriodic = TRUE;
  401.         }
  402.         else {
  403.         *ErrStr = "KV expected";
  404.         *ErrLine = _IPStream[Handler].LineNum;
  405.         CagdSrfFree(NewSrf);
  406.         return NULL;
  407.         }
  408.     }
  409.     else
  410.         KVPeriodic = FALSE;
  411.  
  412.     if (k == 0) {
  413.         NewSrf -> UPeriodic = KVPeriodic;
  414.         if (KVPeriodic) {
  415.         /* Make Knot vector longer. */
  416.         IritFree((VoidPtr) NewSrf -> UKnotVector);
  417.         NewSrf -> UKnotVector =
  418.             (CagdRType *) IritMalloc(sizeof(CagdRType) *
  419.                          (NewSrf -> UOrder +
  420.                           NewSrf -> ULength +
  421.                           NewSrf -> UOrder - 1));
  422.         }
  423.         KnotVector = NewSrf -> UKnotVector;
  424.         KVLen = NewSrf -> UOrder + NewSrf -> ULength +
  425.                 (KVPeriodic ? NewSrf -> UOrder - 1 : 0);
  426.     }
  427.     else {
  428.         NewSrf -> VPeriodic = KVPeriodic;
  429.         if (KVPeriodic) {
  430.         /* Make Knot vector longer. */
  431.         IritFree((VoidPtr) NewSrf -> VKnotVector);
  432.         NewSrf -> VKnotVector =
  433.             (CagdRType *) IritMalloc(sizeof(CagdRType) *
  434.                          (NewSrf -> VOrder +
  435.                           NewSrf -> VLength +
  436.                           NewSrf -> VOrder - 1));
  437.         }
  438.         KnotVector = NewSrf -> VKnotVector;
  439.         KVLen = NewSrf -> VOrder + NewSrf -> VLength +
  440.                 (KVPeriodic ? NewSrf -> VOrder - 1 : 0);
  441.     }
  442.  
  443.     for (i = 0; i < KVLen; i++) {
  444.         if ((Token = _IPGetToken(Handler, StringToken)) !=
  445.                                  IP_TOKEN_OTHER ||
  446.             sscanf(StringToken, IP_FLOAT_READ, &KnotVector[i]) != 1) {
  447.             *ErrStr = "Numeric data expected";
  448.         *ErrLine = _IPStream[Handler].LineNum;
  449.         CagdSrfFree(NewSrf);
  450.         return NULL;
  451.         }
  452.     }
  453.  
  454.     if ((Token = _IPGetToken(Handler, StringToken)) !=
  455.                               IP_TOKEN_CLOSE_PAREN) {
  456.         *ErrStr = "\"]\" expected";
  457.         *ErrLine = _IPStream[Handler].LineNum;
  458.         CagdSrfFree(NewSrf);
  459.         return NULL;
  460.     }
  461.     }
  462.  
  463.     /* Read the points themselves: */
  464.     MaxCoord = CAGD_NUM_OF_PT_COORD(PType);
  465.     for (i = 0; i < ULength * VLength; i++) {
  466.     if ((Token = _IPGetToken(Handler, StringToken)) !=
  467.                             IP_TOKEN_OPEN_PAREN) {
  468.         *ErrStr = "\"[\" expected";
  469.         *ErrLine = _IPStream[Handler].LineNum;
  470.         CagdSrfFree(NewSrf);
  471.         return NULL;
  472.     }
  473.     if (CAGD_IS_RATIONAL_PT(PType)) {
  474.         if ((Token = _IPGetToken(Handler, StringToken)) !=
  475.                                  IP_TOKEN_OTHER ||
  476.             sscanf(StringToken, IP_FLOAT_READ,
  477.                            &NewSrf -> Points[0][i]) != 1) {
  478.         *ErrStr = "Numeric data expected";
  479.         *ErrLine = _IPStream[Handler].LineNum;
  480.         CagdSrfFree(NewSrf);
  481.         return NULL;
  482.         }
  483.     }
  484.     for (j = 1; j <= MaxCoord; j++) {
  485.         if ((Token = _IPGetToken(Handler, StringToken)) !=
  486.                                  IP_TOKEN_OTHER ||
  487.             sscanf(StringToken, IP_FLOAT_READ,
  488.                            &NewSrf -> Points[j][i]) != 1) {
  489.         *ErrStr = "Numeric data expected";
  490.         *ErrLine = _IPStream[Handler].LineNum;
  491.         CagdSrfFree(NewSrf);
  492.         return NULL;
  493.         }
  494.     }
  495.     if ((Token = _IPGetToken(Handler, StringToken)) !=
  496.                                IP_TOKEN_CLOSE_PAREN) {
  497.         *ErrStr = "\"]\" expected";
  498.         *ErrLine = _IPStream[Handler].LineNum;
  499.         CagdSrfFree(NewSrf);
  500.         return NULL;
  501.     }
  502.     }
  503.     if ((Token = _IPGetToken(Handler, StringToken)) != IP_TOKEN_CLOSE_PAREN) {
  504.         *ErrStr = "\"]\" expected";
  505.     *ErrLine = _IPStream[Handler].LineNum;
  506.     CagdSrfFree(NewSrf);
  507.     return NULL;
  508.     }
  509.  
  510.     *ErrStr = NULL;
  511.     *ErrLine = _IPStream[Handler].LineNum;
  512.  
  513.     return NewSrf;
  514. }
  515.